package org.example.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.example.entity.OnlineDeviceInfo;
import org.example.entity.requestbody.KeyFilter;
import org.example.service.CustomerDeviceService;
import org.example.service.QueryDataTask;
import org.example.thread.ThreadPoolManager;
import org.example.util.ChargeStatusUtil;
import org.example.util.DateUtil;
import org.example.util.constantUtil.ConstantUtil;
import org.example.util.DeviceUtil;
import org.example.util.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PreDestroy;

import static org.example.enums.OnOffStatus.*;
import static org.example.enums.ResultCode.FAIL;

import java.util.*;
import java.util.concurrent.*;


@Service
@Slf4j
public class CustomerDeviceServiceImpl implements CustomerDeviceService {
    private ExecutorService executorService= ThreadPoolManager.executorService;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private TimeseriesService timeseriesService;
    @Autowired
    private EntityQueryService entityQueryService;
//
//    public CustomerDeviceServiceImpl(){
//        // 创建线程池
//        int corePoolSize=Runtime.getRuntime().availableProcessors(); // 获取核心线程数，使用机器处理器核心数量
//        log.info("线程池创建{}",corePoolSize);
//        this.executorService = Executors.newFixedThreadPool(2*corePoolSize);  // 线程池大小设置为核心线程数的两倍
//    }
//
//    @PreDestroy
//    public void cleanUp() {
//        // 在销毁服务时关闭线程池
//        log.info("executorService Closed!");
//        executorService.shutdown();
////        try {
////            executorService.awaitTermination(30, TimeUnit.SECONDS);
////        } catch (InterruptedException e) {
////            // 处理异常
////        }
//    }

    public Result getOnlineDeviceByEntityQuery(String customerTitle,String token){
        if(!DeviceUtil.customerTitleDeviceList.containsKey(customerTitle)) return Result.fail("customerTitle "+customerTitle+" not existed!");
        // onOffStatus=1条件：
        // 1. 查询所有在线设备
        // 构造筛选列表
        // entityQuery筛选not_contains(W02) && lifeTs在5min以内即ts字段>五分钟前的时间戳 （筛掉3馈电4欠压）
        // firstError无单体欠压报警
        KeyFilter<String> firstErrorKeyFilter=new KeyFilter<>("firsterror_set","TIME_SERIES","STRING","STRING","NOT_CONTAINS","W02",null);
        // secondError无单体欠压报警
        KeyFilter<String> secondErrorKeyFilter=new KeyFilter<>("seconderror_set","TIME_SERIES","STRING","STRING","NOT_CONTAINS","W02",null);
        // 最新时间大于五分钟前的时间戳
        long ts5Min=DateUtil.getTimestampMinutesBefore(5);
        KeyFilter<Long> lifeTsKeyFilter=new KeyFilter<>("DATE_TIME2","TIME_SERIES","NUMERIC","NUMERIC","GREATER",ts5Min,null);
        List<KeyFilter<?>> keyFilterList=new ArrayList<>();
        keyFilterList.add(firstErrorKeyFilter);
        keyFilterList.add(secondErrorKeyFilter);
        keyFilterList.add(lifeTsKeyFilter);
        Result filterResult=entityQueryService.entityQuery(keyFilterList,token);
        if(!filterResult.getSuccess()) return filterResult;
        Map<String,String> devices=(Map<String,String>) filterResult.getData();

        // 2.遍历所有在线设备，筛选符合该项目号的设备以及非新建的设备
        Map<String,String> deviceMap=new HashMap<>();

        for(Map.Entry<String,String> entry:devices.entrySet()){
            String imei=entry.getKey();
            String uuid=entry.getValue();
            // 2.1 筛选该项目号的设备
            if(DeviceUtil.ImeiCustomerTitle.get(imei)==null || !DeviceUtil.ImeiCustomerTitle.get(imei).equals(customerTitle)) continue;  // 项目号不匹配
            // 2.2 筛选非新建的设备
            Long createdTs=DeviceUtil.ImeiCreatedTime.get(imei);
            if(createdTs==null) continue;
            long nowTs=System.currentTimeMillis();
            int totalDays= DateUtil.getDaysBetween(createdTs,nowTs);
            if(totalDays<1) continue;  // 创建时间小于1天的跳过

            deviceMap.put(imei,uuid);
        }

        // 3.依次查询该项目号下所有在线设备的信息
        List<Map<String,Object>> onlineDeviceList=getDeviceInfoNormal(deviceMap,token);  // 常规实现
//        List<Map<String,Object>> onlineDeviceList=getDeviceInfoMultiThread(deviceMap,token);  // 多线程实现


        // 4. 添加在线率等信息并返回
        int onlineDeviceNum=deviceMap.size();
        int allDeviceNum=DeviceUtil.customerTitleDeviceList.get(customerTitle).size();
        String onlineRate=String.format("%.3f", onlineDeviceNum*1.0/allDeviceNum);
        log.info("customerTitle:{}, online:{}, all:{},rate:{}",customerTitle,onlineDeviceNum,allDeviceNum,onlineRate);
        OnlineDeviceInfo onlineDeviceInfo=new OnlineDeviceInfo();
        onlineDeviceInfo.setCustomerTitle(customerTitle);
        onlineDeviceInfo.setTotalDeviceNum(allDeviceNum);
        onlineDeviceInfo.setOnlineDeviceNum(onlineDeviceNum);
        onlineDeviceInfo.setOnlineRate(Double.parseDouble(onlineRate));
        onlineDeviceInfo.setOnlineDevices(onlineDeviceList);

        return Result.ok(onlineDeviceInfo);
    }
    // 查询在线设备信息非多线程实现
    private List<Map<String,Object>> getDeviceInfoNormal(Map<String,String> deviceMap,String token){
        List<Map<String,Object>> onlineDeviceList=new ArrayList<>();

        for(Map.Entry<String,String> device:deviceMap.entrySet()){
            String imei=device.getKey();
            String uuid=device.getValue();
            Map<String,Object> onlineDevice=new HashMap<>();
            Map<String,Object> result = timeseriesService.getTimeseries(uuid, token);

            // 添加在线设备信息
            if(result.get("message")!=null){
                onlineDevice.put("imei",imei);
                onlineDevice.put("uuid",uuid);
                onlineDevice.put("success",false);
                onlineDevice.put("msg",result.get("message"));
                onlineDeviceList.add(onlineDevice);
                continue;
            }
            // imei号
            onlineDevice.put("imei",result.get("imei"));
            //packNo
            onlineDevice.put("packNo",result.get("PACK_SN"));
            // 充电状态
            if(result.get("Battery_Status")!=null){
                int chargeStatus = Integer.parseInt((String)result.get("Battery_Status"));
                onlineDevice.put("chargeStatus",ChargeStatusUtil.decode(chargeStatus));
            }
            // 电池总压
            if(result.get("rackTotalVoltage")!=null){
                onlineDevice.put("rackTotalVoltage",Double.parseDouble((String)result.get("rackTotalVoltage")));
            }
            onlineDeviceList.add(onlineDevice);
        }
        return onlineDeviceList;
    }
    // 查询在线设备信息多线程实现 @todo 暂时无法使用，正在排查bug
    private List<Map<String,Object>> getDeviceInfoMultiThread(Map<String,String> deviceMap,String token){
        List<Map<String,Object>> onlineDeviceList=new ArrayList<>();
        List<Future<Map<String,Object>>> futures = new ArrayList<>();
        for(Map.Entry<String,String> device:deviceMap.entrySet()){
            String imei=device.getKey();
            String uuid=device.getValue();
            Future<Map<String,Object>> future = executorService.submit(new QueryDataTask(uuid, token));  // 提交任务查询数据
            futures.add(future);  // 结果添加到列表
        }
        List<String> timeOutDevices = new ArrayList<>();
        List<String> interruptedDevices = new ArrayList<>();
        for (Future<Map<String,Object>> future : futures){
            Map<String,Object> onlineDevice=new HashMap<>();
            try{
                Map<String,Object> result = future.get(10, TimeUnit.SECONDS); // 阻塞等待任务执行完成并获取结果
                if(result.get("message")!=null){
                    onlineDevice.put("success",false);
                    onlineDevice.put("uuid",result.get("uuid"));
                    onlineDevice.put("imei",DeviceUtil.getKey(result.get("uuid").toString()));
                    onlineDevice.put("msg",result.get("message"));
                    onlineDeviceList.add(onlineDevice);
                    continue;
                }
                // imei号
                onlineDevice.put("imei",result.get("imei"));
                //packNo
                onlineDevice.put("packNo",result.get("PACK_SN"));
                // 充电状态
                if(result.get("Battery_Status")!=null){
                    int chargeStatus = Integer.parseInt((String)result.get("Battery_Status"));
                    onlineDevice.put("chargeStatus",ChargeStatusUtil.decode(chargeStatus));
                }
                // 电池总压
                if(result.get("rackTotalVoltage")!=null){
                    onlineDevice.put("rackTotalVoltage",Double.parseDouble((String)result.get("rackTotalVoltage")));
                }
                onlineDeviceList.add(onlineDevice);

            }
            // @todo 这里有问题，每个循环写入一次会导致大量异常时导致接口整个崩溃
            catch (TimeoutException | InterruptedException | ExecutionException e) {
                // 处理异常
                log.error("MultiThread Exception!",e);
            }
        }
        return onlineDeviceList;
    }



    public Result getOnlineDevice(String customerTitle, String token) {
        // 首先刷新设备列表保证设备列表最新======删除，不需要刷新，严重影响效率
//        long minutesSinceLastRefresh = DeviceUtil.getLastRefreshDuration();
//        if(minutesSinceLastRefresh>=5){
//            System.out.println("out of 5 min, refresh!");
//            DeviceUtil.refreshDevice(username,password);
//        }

        // 再获取该设备号下所有项目
        Map<String,String> imeiTouuid=new HashMap<>();
        OnlineDeviceInfo onlineDeviceInfo=new OnlineDeviceInfo();
        // 遍历设备列表，筛选该项目号的设备
        for(String imei : DeviceUtil.ImeiCustomerTitle.keySet()){
            // 1.获取设备项目号
            String title=DeviceUtil.ImeiCustomerTitle.get(imei);
            System.out.println("imei to customerTitle "+imei+":"+title);
            if(customerTitle==null || title==null){
                continue;
            }
            // 2.筛选传入的项目号的设备
            if(title.equals(customerTitle)){ // 项目号匹配
                // 获取设备的uuid，用于获取设备信息
                String uuid=deviceService.getUUIDByImei(imei);
                imeiTouuid.put(imei,uuid);
            }
        }
        // 3.查询该项目号下所有设备信息，筛选在线状态
        List<Map<String,Object>> onlineDeviceList=new LinkedList<>();  // 用于存储所有在线设备信息
        int onlineDeviceNum=0;  // 在线设备数量
        int allDeviceNum=imeiTouuid.size();  // 该项目号的所有设备数量
        System.out.println("customerTitle:"+customerTitle+" DeviceNum:"+allDeviceNum);

        /**
         * 查询该项目号下所有设备信息，需要使用多线程来执行查询任务
         */
        // 创建线程池
//        int corePoolSize=Runtime.getRuntime().availableProcessors(); // 获取核心线程数，使用机器处理器核心数量
//        ExecutorService executorService = Executors.newFixedThreadPool(2*corePoolSize);  // 线程池大小设置为核心线程数的两倍
//        ExecutorService executorService = Executors.newCachedThreadPool();  // 动态大小

        // 创建一个列表来保存所有任务的结果。
        List<Future<Map<String,Object>>> futures = new ArrayList<>();

        // 遍历需要查询的数据，为每个数据创建一个任务，并将任务提交给线程池执行。
        for(String imei: imeiTouuid.keySet()){
            String uuid=imeiTouuid.get(imei);
            Future<Map<String,Object>> future = executorService.submit(new QueryDataTask(uuid, token));  // 提交任务查询数据
            futures.add(future);  // 结果添加到列表
        }

        // 等待所有任务执行完成，并收集结果。
        for (Future<Map<String,Object>> future : futures) {
            try {
                Map<String,Object> result = future.get(); // 阻塞等待任务执行完成并获取结果

                // 处理代码，判断设备在线状态并添加在线设备信息
                if(result.get("message")!=null){
                    log.error("Timeseries error");
                    return new Result(FAIL.code, false, null,(String)result.get("message"));
//                    continue;
                }
                // 获取最新B1帧的时间，若没有B1帧认为不在线
                String lifeTs=(String)result.get("Life_ts");
                if(lifeTs==null){
//                    return new Result(FAIL.code, false, null,"Cannot get Life_ts"+result.get("imei"));
                    continue;
                }
                // 判断在线离线状态(只判断了在线、休眠、离线三种状态)
                int onOffStatus=OnOffStatusService.judgeOnOffStatus(lifeTs);
                System.out.println(" onOffStatus:"+onOffStatus);

                // 若为在线设备，则查询基础信息并将其添加到在线设备列表
                if(onOffStatus==ONLINE.onOffStatus){
                    Map<String,Object> onlineDevice=new HashMap<>();
                    // imei号
                    onlineDevice.put("imei",result.get("imei"));
                    //packNo
                    onlineDevice.put("packNo",result.get("PACK_SN"));
                    // 充电状态
                    if(result.get("Battery_Status")!=null){
                        int chargeStatus = Integer.parseInt((String)result.get("Battery_Status"));
                        onlineDevice.put("chargeStatus",ChargeStatusUtil.decode(chargeStatus));
                    }
                    // 电池总压
                    if(result.get("rackTotalVoltage")!=null){
                        onlineDevice.put("rackTotalVoltage",Double.parseDouble((String)result.get("rackTotalVoltage")));
                    }
                    // 添加到在线设备列表
                    onlineDeviceNum++;
                    onlineDeviceList.add(onlineDevice);
                }
            } catch (InterruptedException | ExecutionException e) {
                // 处理异常
                log.error("MultiThread Exception! ",e);
            }
        }
//        executorService.shutdown();

        String onlineRate=String.format("%.3f", onlineDeviceNum*1.0/allDeviceNum);
        onlineDeviceInfo.setCustomerTitle(customerTitle);
        onlineDeviceInfo.setTotalDeviceNum(allDeviceNum);  // 设置设备总数
        onlineDeviceInfo.setOnlineDeviceNum(onlineDeviceNum);  // 设置在线设备数量
        onlineDeviceInfo.setOnlineRate(Double.parseDouble(onlineRate));  // 设置在线率
        onlineDeviceInfo.setOnlineDevices(onlineDeviceList);  // 设置在线设备信息

        return Result.ok(onlineDeviceInfo);
    }

}


